﻿using System;
using System.Collections.Generic;

namespace Allegro.TaskExecution
{
    //using BasicTask = BasicTask<IExecutionContext>;

    /// <summary>
    /// Delegate for execution in a task execution context
    /// </summary>
    /// <param name="context"></param>
    /// <returns></returns>
    public delegate object ExecuteInContext(IExecutionContext context);
    /// <summary>
    /// Delegate for execution in a task execution context
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="C"></typeparam>
    /// <param name="context"></param>
    /// <returns></returns>
    public delegate T ExecuteInContext<T, C>(C context) where C : IExecutionContext;
    /// <summary>
    /// Delegate for execution in a task execution context
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="C"></typeparam>
    /// <param name="task"></param>
    /// <param name="context"></param>
    /// <returns></returns>
    public delegate T ExecuteInTaskContext<T, C>(ITask task, C context) where C : IExecutionContext;

    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="C"></typeparam>
    [Obsolete("Use the RunActivity task instead")]
    public class BasicTask<T, C> : Task where C : IExecutionContext
    {
        ///<summary>
        ///</summary>
        public ExecuteInContext<T, C> Executor;
        ///<summary>
        ///</summary>
        public ExecuteInTaskContext<T, C> TaskExecutor;
        ///<summary>
        ///</summary>
        public ExecuteInContext GeneralExecutor;
        /// <summary>
        /// 
        /// </summary>
        public BasicTask()
        {
            
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="executor"></param>
        public BasicTask(ExecuteInContext executor)
        {
            GeneralExecutor = executor;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="executor"></param>
        public BasicTask(ExecuteInContext<T, C> executor)
        {
            Executor = executor;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="executor"></param>
        public BasicTask(ExecuteInTaskContext<T, C> executor)
        {
            TaskExecutor = executor;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="activity"></param>
        public BasicTask(ITaskActivity activity)
        {
            Activity = activity;
            //Activity.SpawningTask = this;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        protected override void ExecuteTask(IExecutionContext context)
        {
            if (context is C)
            {
                IAtomicTaskActivity activity = Activity as IAtomicTaskActivity;
                T result = default(T);
                if (activity != null)
                {
                    if (activity.CanExecute(context))
                    {
                        activity.Execute(this, context);
                    }
                }
                else if ( Executor != null)
                {
                    result = Executor((C) context);
                }
                else if (TaskExecutor != null)
                {
                    result = TaskExecutor(this, (C) context);
                }
            }
        }
    }
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="C"></typeparam>
    [Obsolete("Use the RunActivity task instead")]
    public class BasicTask<C> : Task where C : IExecutionContext
    {
        /// <summary>
        /// 
        /// </summary>
        public BasicTask()
        {
            
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="activity"></param>
        public BasicTask(ITaskActivity activity)
        {
            Activity = activity;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        protected override void ExecuteTask(IExecutionContext context)
        {
            if (context is C)
            {
                IAtomicTaskActivity activity = Activity as IAtomicTaskActivity;
                if (activity != null)
                {
                    if (activity.CanExecute(context))
                    {
                        activity.Execute(this, context);
                    }
                    else
                    {
                        // todo: Must handle this
                    }
                }
                else
                {
                    string msg = "Basic task not initialized. Missing activity";
                    Log.Error(msg, this, LogEventTypes.TaskEvent);
                    throw new ApplicationException(msg);
                }
            }
            else
            {
                string msg = "Illegal context argument";
                Log.Error(msg, this, LogEventTypes.TaskEvent);
                throw new ArgumentException(msg);
            }
        }
    }
    /// <summary>
    /// 
    /// </summary>
    [Obsolete("Use the RunActivity task instead")]
    public class BasicTask: Task
    {
        /// <summary>
        /// 
        /// </summary>
        public ExecuteInContext<object, IExecutionContext> Executor;
        /// <summary>
        /// 
        /// </summary>
        public ExecuteInTaskContext<object, IExecutionContext> TaskExecutor;

        /// <summary>
        /// Predicate. If not set or evaluates to true, the task will run, otherwise not
        /// </summary>
        public IExecutionCondition If { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public BasicTask()
        {

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="activity"></param>
        public BasicTask(ITaskActivity activity)
        {
            Activity = activity;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="executor"></param>
        public BasicTask(ExecuteInContext<object, IExecutionContext> executor)
        {
            Executor = executor;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="executor"></param>
        public BasicTask(ExecuteInTaskContext<object, IExecutionContext> executor)
        {
            TaskExecutor = executor;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        protected override void ExecuteTask(IExecutionContext context)
        {
            object result = null;

            // Navigate to the task execution context
            IExecutionContext executionContext = GetTaskExecutionContext(this, context);

            // Check the condition
            if (If != null && !If.IsTrue(executionContext))
                return;

            // Check if the execution should be suspended or aborted
            CheckIfSuspendOrAbort(executionContext);

            IAtomicTaskActivity activity = Activity as IAtomicTaskActivity;
            if (activity != null)
            {
                if (activity.CanExecute(executionContext))
                {
                    activity.Execute(this, executionContext);
                }
                else
                {
                    // todo: Must handle this
                }
            }
            else if (Executor != null)
            {
                result = Executor(executionContext);
            }
            else if (TaskExecutor != null)
            {
                result = TaskExecutor(this, executionContext);
            }
            else
            {
                string msg = string.Format("Illegal context argument when executing BasicTask {0}", Name);
                Log.Error(msg, this, LogEventTypes.TaskEvent);
                throw new ArgumentException(msg);
            }
        }
    }
}
